OpenRoads Designer CONNECT Edition SDK Help

PI alignment creator

Description

  • This is a custom interactive tool for creating complex alignment by PI .

  • The user is prompted to place data points. As the user places points, they are temporarily linked by a visible line, and from the second point onward, the user is prompted for the arc radius, feature definition, and start and end spiral lengths for the next angle. When the user right-clicks, a complex horizontal alignment is created from the points where a curve set composed of spirals and arcs is created at each PI.

  • The PIAlignmentCreator class which extends DgnElementSetTool which handles different events to interact with UI, the PIAlignmentCreator class overrides the events here in this tool .

Remarks

  • This sample code is a part of ManagedSDKExample which you get with SDK installation under "examples" section in SDK installation directory.

  • If you encounter any error while using DgnElementSetTool class, make sure to add a reference to Bentley.DgnDisplayNet.dll by selecting Project > Add Reference or change the projects .csproj file to add reference to this dll .

  • The default dll location will be "C:\Program Files\Bentley\OpenRoads Designer CE 10.11\OpenRoadsDesigner\Bentley.DgnDisplayNet.dll".

Source Code

//Required References

using System.Collections.Generic;
using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.Elements;
using Bentley.CifNET.LinearGeometry;
using Bentley.GeometryNET;
using Bentley.MstnPlatformNET;
using Bentley.CifNET.GeometryModel.SDK;
using Bentley.CifNET.GeometryModel.SDK.Edit;
using Bentley.CifNET.SDK.Edit;
using System.Windows.Forms;
using Bentley.CifNET.Formatting;

namespace ManagedSDKExample.Examples
{
    class PIAlignmentCreator : DgnElementSetTool
    {
        internal static DgnModel activeModel = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();
        internal static ModelInfo info = activeModel.GetModelInfo();
        private double UOR_TO_METER = 1.0 / info.UorPerMeter;

        internal static double m_defaultUnitsToMeters = FormatSettingsConstants.GetMasterUnitsToMeters();
        private double MASTER_TO_METER = 1.0 * m_defaultUnitsToMeters;
        List<HorizontalPI> m_horizontalPI = new List<HorizontalPI>();
        string m_featureDef;

        /*----------------------------------------------------------------------------------------------**/
        /* Write Function | The user is prompted to place data points. As the user places points, they are temporarily
         *                  linked by a visible line, and from the second point onward, the user is prompted
         *                  for the arc radius, feature definition, and start and end spiral lengths for the next
         *                  angle. When the user right-clicks, a complex horizontal alignment is created
         *                  from the points where a curve set composed of spirals and arcs is created at each PI.
        /*--------------+---------------+---------------+---------------+---------------+----------------*/
        internal void CreatePIAlignmentFromPoints()
        {
            List<LinearElement> linElems = new List<LinearElement>();

            //adjusts x and y values
            for (int i = 0; i < m_horizontalPI.Count; i++)
            {
                m_horizontalPI[i].Coordinate.X *= UOR_TO_METER;
                m_horizontalPI[i].Coordinate.Y *= UOR_TO_METER;
                m_horizontalPI[i].Coordinate.Z *= UOR_TO_METER;
                m_horizontalPI[i].Radius *= MASTER_TO_METER;
            }

            if (m_horizontalPI.Count <= 1)
                return;
            else if (m_horizontalPI.Count == 2)
            {
                linElems.Add(Line.Create1(m_horizontalPI[0].Coordinate, m_horizontalPI[1].Coordinate));
            }
            else
            {
                for (int i = 0; i < m_horizontalPI.Count - 2; i++)
                {
                    List<LinearElement> tempLinElems = GetArcBetweenTwoElements(m_horizontalPI[i].Coordinate, m_horizontalPI[i + 1].Coordinate, m_horizontalPI[i + 1].Coordinate, m_horizontalPI[i + 2].Coordinate, m_horizontalPI[i + 1].Radius);
                    if (tempLinElems.Count > 0)
                        linElems.AddRange(tempLinElems);
                    else
                    {
                        MessageBox.Show("At least one tangent is too short for its given radius. Try again.");
                        return;
                    }
                }
            }

            //create geometry objects using native objects inside Bentley.CifNET.LinearGeometry
            LinearComplex complexAlign = LinearComplex.Create1(linElems.ToArray(), false, false, 0.001);

            //ConsensusConnectionEdit allows the persistence of civil objects to the DGN file
            ConsensusConnectionEdit con = ConsensusConnectionEdit.GetActive();

            GeometricModel gm = con.GetOrCreateGeometricModel();

            if (gm == null)
            {
                con.Close();
                con.Dispose();
                return;
            }

            //begins mode to persist objects
            con.StartTransientMode();
            //create SDK.Edit alignment objects from native objects
            Bentley.CifNET.GeometryModel.SDK.Alignment al = gm.CreateAlignmentByLinearElement(complexAlign, true);
            //persists objects created in persist mode
            con.PersistTransients();

            //sets feature definition
            if (m_featureDef != null && m_featureDef != string.Empty)
            {
                al.SetFeatureDefinition(m_featureDef);
            }

        }

        /*------------------------------------------------------------------------------------**/
        /* Creation
        /*--------------+---------------+---------------+---------------+---------------+------*/
        //Caller must check that the number of elements in the returned list is greater than 0
        //Expected input data format: meters
        public static List<LinearElement> GetArcBetweenTwoElements(Bentley.GeometryNET.DPoint3d firstTangentStartPoint, Bentley.GeometryNET.DPoint3d firstTangentEndPoint,
            Bentley.GeometryNET.DPoint3d lastTangentStartPoint, Bentley.GeometryNET.DPoint3d lastTangentEndPoint, double arcRadius)
        {
            //setup
            List<LinearElement> linElems = new List<LinearElement>();

            //creating the first tangent line            
            Line firstTangentLine = Line.Create1(firstTangentStartPoint, firstTangentEndPoint);

            //creating the last tangent line
            Line lastTangentLine = Line.Create1(lastTangentStartPoint, lastTangentEndPoint);

            //getting the angle between lines
            double angleBetweenLines = firstTangentLine.Direction - lastTangentLine.Direction;
            if (angleBetweenLines < 0) angleBetweenLines += 2 * System.Math.PI;

            Hand hand;
            Line firstTangentOffset, lastTangentOffset;
            //If the angle created by the lines is less than 180 degrees, creates a clockwise arc using offset lines in the positive direction to find the center point
            if (angleBetweenLines < System.Math.PI)
            {
                hand = Hand.Clockwise;
                firstTangentOffset = Line.Create1(firstTangentLine.GetPointAtDistanceOffset(0.0, arcRadius).Coordinates, firstTangentLine.GetPointAtDistanceOffset(firstTangentLine.Length, arcRadius).Coordinates);
                lastTangentOffset = Line.Create1(lastTangentLine.GetPointAtDistanceOffset(0.0, arcRadius).Coordinates, lastTangentLine.GetPointAtDistanceOffset(lastTangentLine.Length, arcRadius).Coordinates);
            }
            //If the angle created by the lines is greater than 180 degrees, creates a counterclockwise arc using offset lines in the negative direction to find the center point
            else
            {
                hand = Hand.CounterClockwise;
                firstTangentOffset = Line.Create1(firstTangentLine.GetPointAtDistanceOffset(0.0, -arcRadius).Coordinates, firstTangentLine.GetPointAtDistanceOffset(firstTangentLine.Length, -arcRadius).Coordinates);
                lastTangentOffset = Line.Create1(lastTangentLine.GetPointAtDistanceOffset(0.0, -arcRadius).Coordinates, lastTangentLine.GetPointAtDistanceOffset(lastTangentLine.Length, -arcRadius).Coordinates);
            }

            //getting the intersection of the offset lines
            LinearIntersectionCollection intersectionCollection = firstTangentOffset.Intersect(lastTangentOffset);
            if (intersectionCollection.Count > 0)
            {
                //the intersection of the offset lines is the center point of the arc
                Bentley.GeometryNET.DPoint3d centerPoint = intersectionCollection.Item(0).PointOn1.Coordinates;

                //getting lines perpendicular from the center point to the tangent lines to find the start and end points of the arc
                LinearPoint startPointLinear = firstTangentLine.ProjectPointOnPerpendicular(centerPoint);
                Bentley.GeometryNET.DPoint3d arcStartPoint = startPointLinear.Coordinates;
                Line startDirectionLine = Line.Create1(centerPoint, arcStartPoint);

                LinearPoint endPointLinear = lastTangentLine.ProjectPointOnPerpendicular(centerPoint);
                Bentley.GeometryNET.DPoint3d arcEndPoint = endPointLinear.Coordinates;
                Line endDirectionLine = Line.Create1(centerPoint, arcEndPoint);

                //creating the starting tangent to the arc
                Line startingTangent = Line.Create1(firstTangentStartPoint, arcStartPoint);
                linElems.Add(startingTangent);

                //creating the arc
                Bentley.CifNET.LinearGeometry.CircularArc arc = Bentley.CifNET.LinearGeometry.CircularArc.Create8(centerPoint, arcRadius, startDirectionLine.Direction, endDirectionLine.Direction, hand);
                linElems.Add(arc);

                //creating the ending tangent to the arc
                Line endLine = Line.Create1(arcEndPoint, lastTangentEndPoint);
                linElems.Add(endLine);
            }

            return linElems;
        }
        private DPoint3d GetMidPoint(DPoint3d pt1, DPoint3d pt2)
        {
            DPoint3d newPt = new DPoint3d();
            newPt.X = (pt1.X + pt2.X) / 2;
            newPt.Y = (pt1.Y + pt2.Y) / 2;
            return newPt;
        }

        protected override void OnPostInstall()
        {
            NotificationManager.OutputPrompt("Select first data point.");
            BeginDynamics();
        }

        //adds points on click
        protected override bool OnDataButton(DgnButtonEvent ev)
        {
            if (m_horizontalPI.Count == 0)
            {
                m_horizontalPI.Add(new HorizontalPI { Coordinate = ev.Point });
                BeginDynamics();
                NotificationManager.OutputPrompt("Select next data point or right click to complete the command.");
            }
            else if (m_horizontalPI.Count > 0)
            {
                m_horizontalPI.Add(new HorizontalPI { Coordinate = ev.Point, Radius = 300 });
                m_featureDef = "Alignment\\Geom_Baseline";
            }

            return false;
        }

        //calls command on reset (right click)
        protected override bool OnResetButton(DgnButtonEvent ev)
        {
            CreatePIAlignmentFromPoints();
            EndDynamics();
            m_horizontalPI.Clear();
            NotificationManager.OutputPrompt("Command complete. Select first data point or pick element selection tool to exit command.");
            return false;
        }

        //allows preview lines to be drawn
        protected override void OnDynamicFrame(DgnButtonEvent ev)
        {
            RedrawElems redraw = new RedrawElems();
            redraw.DrawMode = DgnDrawMode.TempDraw;
            redraw.DrawPurpose = DrawPurpose.Dynamics;
            redraw.SetViewport(ev.Viewport);

            if (m_horizontalPI.Count > 1)
            {
                List<DPoint3d> points = new List<DPoint3d>();
                foreach (HorizontalPI hpi in m_horizontalPI)
                    points.Add(hpi.Coordinate);

                LineStringElement lse = new LineStringElement(Session.Instance.GetActiveDgnModel(), null, points.ToArray());
                redraw.DoRedraw(lse);
            }
        }

        protected override void OnRestartTool()
        {
            InstallNewInstance();
        }

        public override StatusInt OnElementModify(Element element)
        {
            return StatusInt.Error;
        }

        public static void InstallNewInstance()
        {
            PIAlignmentCreator tool = new PIAlignmentCreator();
            tool.InstallTool();
        }
    }
}